﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.Advertisement;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Devices.Enumeration;
using Windows.Foundation;
using Windows.Networking;
using Windows.Networking.Proximity;
using Windows.Networking.Sockets;
using Windows.Security.Cryptography;
using Windows.Storage.Streams;

namespace WinFormsBLETest
{
    public class BleCore
    {
        private static object lockedobj = new object();
        public enum MsgType
        {
            NotifyTxt,
            BleData,



            /// <summary>
            /// 搜索到设备
            /// </summary>
            BleDevice,


            BleReadData,
            BleWriteData,
        }

        private Boolean asyncLock = false;

        /// <summary>
        /// 搜索蓝牙设备对象
        /// </summary>
        //private DeviceWatcher deviceWatcher;
        private BluetoothLEAdvertisementWatcher deviceWatcher;

        /// <summary>
        /// 当前连接的服务
        /// </summary>
        public GattDeviceService CurrentService { get; set; }

        /// <summary>
        /// 当前连接的蓝牙设备
        /// </summary>
        public BluetoothLEDevice CurrentDevice { get; set; }

        /// <summary>
        /// 写特征对象
        /// </summary>
        public GattCharacteristic CurrentWriteCharacteristic { get; set; }

        /// <summary>
        /// 通知特征对象
        /// </summary>
        public GattCharacteristic CurrentNotifyCharacteristic { get; set; }

        /// <summary>
        /// 特性通知类型通知启用
        /// </summary>
        private const GattClientCharacteristicConfigurationDescriptorValue CHARACTERISTIC_NOTIFICATION_TYPE = GattClientCharacteristicConfigurationDescriptorValue.Notify;

        /// <summary>
        /// 存储检测到的设备
        /// </summary>
        private Dictionary<string, BluetoothLEDevice> DeviceList = new Dictionary<string, BluetoothLEDevice>();

        /// <summary>
        /// 定义搜索蓝牙设备委托
        /// </summary>
        public delegate void DeviceWatcherChangedEvent(MsgType type, BluetoothLEDevice bluetoothLEDevice);

        /// <summary>
        /// 搜索蓝牙事件
        /// </summary>
        public event DeviceWatcherChangedEvent DeviceWatcherChanged;

        /// <summary>
        /// 获取服务委托
        /// </summary>
        public delegate void GattDeviceServiceAddedEvent(GattDeviceService gattDeviceService);

        /// <summary>
        /// 获取服务事件
        /// </summary>
        public event GattDeviceServiceAddedEvent GattDeviceServiceAdded;

        /// <summary>
        /// 获取特征委托
        /// </summary>
        public delegate void CharacteristicAddedEvent(GattCharacteristic gattCharacteristic);

        /// <summary>
        /// 获取特征事件
        /// </summary>
        public event CharacteristicAddedEvent CharacteristicAdded;

        /// <summary>
        /// 提示信息委托
        /// </summary>
        public delegate void MessAgeChangedEvent(MsgType type, string message, byte[] data = null);

        /// <summary>
        /// 提示信息事件
        /// </summary>
        public event MessAgeChangedEvent MessAgeChanged;

        /// <summary>
        /// 当前连接的蓝牙Mac
        /// </summary>
        private string CurrentDeviceMAC { get; set; }

        public BleCore()
        {

        }

        /// <summary>
        /// 搜索蓝牙设备
        /// </summary>
        public void StartBleDeviceWatcher()
        {
            DeviceList.Clear();

            this.deviceWatcher = new BluetoothLEAdvertisementWatcher();
            this.deviceWatcher.ScanningMode = BluetoothLEScanningMode.Active;//指定活动扫描模式。 这表示将从平台发送扫描请求数据包，以主动查询更多 BluetoothLEAdvertisementType.ScanResponse 类型的广告数据。

            //信号强度过滤
            this.deviceWatcher.SignalStrengthFilter.InRangeThresholdInDBm = -80;
            this.deviceWatcher.SignalStrengthFilter.OutOfRangeThresholdInDBm = -90;
            this.deviceWatcher.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(5000);
            this.deviceWatcher.SignalStrengthFilter.SamplingInterval = TimeSpan.FromMilliseconds(2000);



            this.deviceWatcher.Received += DeviceWatcher_Received;
            this.deviceWatcher.Start();


        }

        private void DeviceWatcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
        {


            BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress).Completed = async (asyncInfo, asyncStatus) =>
            {
                if (asyncStatus == AsyncStatus.Completed)
                {
                    if (asyncInfo.GetResults() != null)
                    {
                        BluetoothLEDevice currentDevice = asyncInfo.GetResults();


                        lock (lockedobj)
                        {
                            Boolean contain = false;
                            if (!DeviceList.ContainsKey(currentDevice.DeviceId))
                            {
                                DeviceList.Add(currentDevice.DeviceId, currentDevice);
                                this.DeviceWatcherChanged(MsgType.BleDevice, currentDevice);
                            }
                        }
                    }
                }
            };
        }
        /// <summary>
        /// 停止搜索蓝牙
        /// </summary>
        public void StopBleDeviceWatcher()
        {
            this.deviceWatcher.Stop();
        }

        /// <summary>
        /// 获取蓝牙服务
        /// </summary>
        public bool FindService(BluetoothLEDevice Device)
        {

            CloseConnect();

            CurrentDeviceMAC = null;


            if(CurrentDevice !=null)
            {
                //CurrentDevice?.Dispose();
            }
            
            CurrentDevice = null;



            this.CurrentDevice = Device;
            this.CurrentDevice.ConnectionStatusChanged += this.CurrentDevice_ConnectionStatusChanged;

            byte[] _Bytes1 = BitConverter.GetBytes(this.CurrentDevice.BluetoothAddress);
            Array.Reverse(_Bytes1);
            this.CurrentDeviceMAC = BitConverter.ToString(_Bytes1, 2, 6).Replace('-', ':').ToLower();


            this.SendConnectEvent();




            //开始获取服务
            this.CurrentDevice.GetGattServicesAsync().Completed = async (asyncInfo, asyncStatus) =>
            {
                if (asyncStatus == AsyncStatus.Completed)
                {
                    if (asyncInfo.GetResults() != null)
                    {
                        var services = asyncInfo.GetResults().Services;
                        foreach (GattDeviceService ser in services)
                        {

                            

                            this.GattDeviceServiceAdded(ser);
                        }

                    }

                }
            };
            return true;
        }

        /// <summary>
        /// 获取特性
        /// </summary>
        public void FindCharacteristic(GattDeviceService gattDeviceService)
        {

            CloseConnect();

            this.CurrentService = gattDeviceService;
            this.CurrentService.GetCharacteristicsAsync().Completed = (asyncInfo, asyncStatus) =>
            {
                if (asyncStatus == AsyncStatus.Completed)
                {
                    lock (lockedobj)
                    {
                        var characteristics = asyncInfo.GetResults().Characteristics;
                        foreach (GattCharacteristic characteristic in characteristics)
                        {
                            
                            this.CharacteristicAdded(characteristic);
                        }
                    }

                }
            };
        }

        /// <summary>
        /// 获取操作
        /// </summary>
        /// <returns></returns>
        public async Task SetOpteron(GattCharacteristic gattCharacteristic)
        {
            gattCharacteristic.ProtectionLevel = GattProtectionLevel.Plain;
            //Debug.Print(gattCharacteristic.Service.Session.MaxPduSize.ToString());

            int isWrite = (int)gattCharacteristic.CharacteristicProperties & (int)GattCharacteristicProperties.Write;
            int isWriteWithoutResponse = (int)gattCharacteristic.CharacteristicProperties & (int)GattCharacteristicProperties.WriteWithoutResponse;
            if (isWrite > 0 || isWriteWithoutResponse > 0)
            {
                this.CurrentWriteCharacteristic = gattCharacteristic;
                this.MessAgeChanged(MsgType.NotifyTxt, gattCharacteristic.Uuid.ToString() + " 此通道为可写");

            }

            int isNotify = (int)gattCharacteristic.CharacteristicProperties & (int)GattCharacteristicProperties.Notify;
            if (isNotify > 0)
            {
                this.CurrentNotifyCharacteristic = gattCharacteristic;
                this.CurrentNotifyCharacteristic.ValueChanged += Characteristic_ValueChanged;
                this.MessAgeChanged(MsgType.NotifyTxt, gattCharacteristic.Uuid.ToString() + " 此通道为通知频道");
                await this.EnableNotifications(gattCharacteristic);
            }

        }

        /// <summary>
        /// 连接蓝牙
        /// </summary>
        /// <returns></returns>
        private async Task SendConnectEvent()
        {
            string msg = "正在连接设备<" + this.CurrentDeviceMAC + ">..";
            this.MessAgeChanged(MsgType.NotifyTxt, msg);

        }

        /// <summary>
        /// 搜索到的蓝牙设备
        /// </summary>
        /// <returns></returns>
        private async Task Matching(string Id)
        {
            try
            {
                BluetoothLEDevice.FromIdAsync(Id).Completed = async (asyncInfo, asyncStatus) =>
                {
                    if (asyncStatus == AsyncStatus.Completed)
                    {
                        BluetoothLEDevice bleDevice = asyncInfo.GetResults();
                        this.DeviceList[bleDevice.DeviceId] = bleDevice;
                        this.DeviceWatcherChanged(MsgType.BleDevice, bleDevice);
                    }
                };
            }
            catch (Exception e)
            {
                string msg = "没有发现设备:" + e.ToString();
                this.MessAgeChanged(MsgType.NotifyTxt, msg);
            }
        }

        /// <summary>
        /// 主动断开连接
        /// </summary>
        /// <returns></returns>
        public void Dispose()
        {

            CurrentDeviceMAC = null;
            CurrentService?.Dispose();
            CurrentDevice?.Dispose();
            CurrentDevice = null;
            CurrentService = null;
            CurrentWriteCharacteristic = null;
            CurrentNotifyCharacteristic = null;
            MessAgeChanged(MsgType.NotifyTxt, "主动断开连接");
        }


        public void CloseConnect()
        {
            CurrentWriteCharacteristic = null;
            if (CurrentNotifyCharacteristic != null)
                CurrentNotifyCharacteristic.ValueChanged -= Characteristic_ValueChanged;
            CurrentNotifyCharacteristic = null;

            if(CurrentService !=null)
            {
                //CurrentService.Session.MaintainConnection = false;

                //CurrentService?.Dispose();
                CurrentService = null;
            }
            

        }

        private void CurrentDevice_ConnectionStatusChanged(BluetoothLEDevice sender, object args)
        {
            if (sender.ConnectionStatus == BluetoothConnectionStatus.Disconnected && CurrentDeviceMAC != null)
            {
                string msg = "设备已断开,自动重连";
                MessAgeChanged(MsgType.NotifyTxt, msg);
                CloseConnect();
                //if (!asyncLock)
                //{
                //    asyncLock = true;
                //    this.CurrentDevice.Dispose();
                //    SelectDeviceFromIdAsync(CurrentDeviceMAC);
                //}
            }
            else
            {
                string msg = "设备已连接";
                MessAgeChanged(MsgType.NotifyTxt, msg);
            }
        }

        /// <summary>
        /// 按MAC地址直接组装设备ID查找设备
        /// </summary>
        public void SelectDeviceFromIdAsync(string MAC)
        {
            CurrentDeviceMAC = MAC;
            CurrentDevice = null;
            BluetoothAdapter.GetDefaultAsync().Completed = async (asyncInfo, asyncStatus) =>
            {
                if (asyncStatus == AsyncStatus.Completed)
                {
                    BluetoothAdapter mBluetoothAdapter = asyncInfo.GetResults();
                    if (mBluetoothAdapter != null)
                    {
                        await Matching(MAC);
                    }
                    else
                    {
                        string msg = "查找连接蓝牙设备异常.";
                        MessAgeChanged(MsgType.NotifyTxt, msg);
                    }
                }
            };
        }

        /// <summary>
        /// 设置特征对象为接收通知对象
        /// </summary>
        /// <param name="characteristic"></param>
        /// <returns></returns>
        public async Task EnableNotifications(GattCharacteristic characteristic)
        {
            string sUUID = characteristic.Uuid.ToString();
            string msg = "收通知对象=" + sUUID;
            this.MessAgeChanged(MsgType.NotifyTxt, msg);

            characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(CHARACTERISTIC_NOTIFICATION_TYPE).Completed = async (asyncInfo, asyncStatus) =>
            {
                if (asyncStatus == AsyncStatus.Completed)
                {
                    GattCommunicationStatus status = asyncInfo.GetResults();
                    if (status == GattCommunicationStatus.Unreachable)
                    {
                        msg = sUUID + " 设备不可用";
                        this.MessAgeChanged(MsgType.NotifyTxt, msg);
                        if (CurrentNotifyCharacteristic != null && !asyncLock)
                        {
                            await this.EnableNotifications(CurrentNotifyCharacteristic);
                        }
                    }
                    asyncLock = false;
                    msg = sUUID + " 设备连接状态" + status;
                    this.MessAgeChanged(MsgType.NotifyTxt, msg);
                }
            };
        }

        /// <summary>
        /// 接受到蓝牙数据
        /// </summary>
        private void Characteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
        {
            byte[] data;
            CryptographicBuffer.CopyToByteArray(args.CharacteristicValue, out data);
            string str = $"{DateTime.Now:HH:mm:ss.fff} 接收-{data.Length}：" + BitConverter.ToString(data);
            Debug.WriteLine(str);
            this.MessAgeChanged(MsgType.BleReadData, str, data);
        }

        /// <summary>
        /// 发送数据接口
        /// </summary>
        /// <returns></returns>
        public async Task Write(byte[] data, bool bShowMessage = true)
        {
            if (CurrentWriteCharacteristic != null)
            {
                CurrentWriteCharacteristic.WriteValueAsync(CryptographicBuffer.CreateFromByteArray(data), GattWriteOption.WriteWithResponse);
                if (bShowMessage)
                {
                    string str = "发送：" + BitConverter.ToString(data);
                    this.MessAgeChanged(MsgType.BleWriteData, str, data);
                }

            }

        }
    }
}